# encoding: utf-8
"""
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    created by lane.chang on '17/10/2024'
    comment: coze平台相关接口
"""
from typing import Any, Mapping

from fastapi import APIRouter, Query, Body, responses
from starlette.requests import Request

from config import Config
from project.core.function import json_response
from project.lib.decorator import api_common, exec_duration
from project.middleware.coze import Coze
from project.model.database.coze import CozeTemp


coze_router = APIRouter(prefix='/u', tags=['user.coze'])


@coze_router.post('/coze/conversation/create', summary='创建会话')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),))
@exec_duration(add_return=True)
async def create_conversation(request: Request,
                              personal_token: str = Body(None, title='个人令牌', description='不传个人令牌时, 服务会自动使用团队令牌'),
                              user_message: str = Body('', title='用户话术'),
                              files: list[str] = Body([], title='文件列表'),
                              images: list[str] = Body([], title='图片列表'),
                              public_key: str = Body(None, title='公钥', description='如果用户上传密钥和OAuth应用id，则优先使用它们获取其个人令牌'),
                              private_key: str = Body(None, title='私钥'),
                              oauth_app_id: str = Body(None, title='oauth应用id'),
                              meta_data: dict = Body({}, title='附加消息')):
    """
    **desc**: 创建会话(支持空会话)

    **url**: http(s)://{0}.udicaria.com/u/coze/conversation/create

    **method**: POST

    **params**:

        <query>:
            personal_token: personal_token(个人令牌)
            user_message: 用户话术
            files: 文件列表(文件id/文件url)
            images: 图片列表(图片id/图片url)

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data: {
                created_at: 创建时间戳,
                id: 会话id,
                meta_data: 附加消息
            }
            exec_time: 接口后端处理时长
        }
    """
    coze = Coze(personal_token=personal_token, public_key=public_key, private_key=private_key, oauth_app_id=oauth_app_id)
    ret_data = await coze.create_conversation(user_message=user_message, files=files, images=images, meta_data=meta_data)

    return json_response(data=ret_data)


@coze_router.get('/coze/conversation/retrieve', summary='查看会话')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),))
@exec_duration(add_return=True)
async def retrieve_conversation(request: Request,
                                personal_token: str = Query(None, title='个人令牌', description='不传个人令牌时, 服务会自动使用团队令牌'),
                                conversation_id: str = Query(..., title='会话id')):
    """
    **desc**: 查看会话信息

    **url**: http(s)://{0}.udicaria.com/u/coze/conversation/retrieve

    **method**: GET

    **params**:

        <query>:
            conversation_id: 会话id

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data: {
                created_at: 创建时间戳,
                id: 会话id,
                meta_data: 附加消息
            }
            exec_time: 接口后端处理时长
        }
    """
    coze = Coze(personal_token=personal_token)
    ret_data = await coze.retrieve_conversation(conversation_id)

    return json_response(data=ret_data)


@coze_router.post('/coze/chat', summary='发起对话')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),))
@exec_duration(add_return=True)
async def do_chat(request: Request,
                  conversation_id: str = Body(None, title='会话id'),
                  personal_token: str = Body(None, title='个人令牌', description='不传个人令牌时, 服务会自动使用团队令牌'),
                  bot_id: str = Body(..., title='智能体id'),
                  user_id: str = Body('123', title='用户id', description='用以区分用户的对话, 目前可以使用终端编号作为用户id'),
                  user_message: str = Body(..., title='用户话术'),
                  files: list[str] = Body([], title='文件列表'),
                  images: list[str] = Body([], title='图片列表'),
                  meta_data: dict = Body({}, title='附加消息')):
    """
    **desc**: 发起对话

    **url**: http(s)://{0}.udicaria.com/u/coze/chat

    **method**: POST

    **params**:

        <body>:
            conversation_id: 会话id(可不传)
            personal_token: personal_token(个人令牌)
            bot_id: 智能体id
            user_id: 用户id
            user_message: 用户话术
            files: 文件列表
            images: 图片列表
            meta_data: 附加消息

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    coze = Coze(personal_token=personal_token)
    ret_data = await coze.chat(bot_id, user_id, user_message, conversation_id, files, images, meta_data)

    return json_response(data=ret_data)


@coze_router.post('/coze/chat/streaming', summary='发起对话(流式)')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),))
@exec_duration(add_return=True)
async def do_chat_streaming(request: Request,
                            conversation_id: str = Body(None, title='会话id'),
                            personal_token: str = Body(None, title='个人令牌', description='不传个人令牌时, 服务会自动使用团队令牌'),
                            public_key: str = Body(None, title='公钥', description='如果用户上传密钥和OAuth应用id，则优先使用它们获取其个人令牌'),
                            private_key: str = Body(None, title='私钥'),
                            oauth_app_id: str = Body(None, title='oauth应用id'),
                            bot_id: str = Body(..., title='智能体id'),
                            user_id: str = Body('123', title='用户id', description='用以区分用户的对话, 目前可以使用终端编号作为用户id'),
                            user_message: str = Body(..., title='用户话术'),
                            files: list[str] = Body([], title='文件列表'),
                            images: list[str] = Body([], title='图片列表'),
                            meta_data: dict = Body({}, title='附加消息'),
                            custom_variables: Mapping[str, str] = Body(None, title='自定义变量')):
    """
    **desc**: 发起对话(流式)

    **url**: http(s)://{0}.udicaria.com/u/coze/chat/streaming

    **method**: POST

    **params**:

        <body>:
            conversation_id: 会话id(可不传)
            personal_token: personal_token(个人令牌)(不传时会使用系统指定的团队令牌)
            public_key: 公钥(如果用户上传密钥和OAuth应用id，则优先使用它们获取其个人令牌)
            private_key: 私钥
            oauth_app_id: oauth应用id
            bot_id: 智能体id
            user_id: 用户id
            user_message: 用户话术
            files: 文件列表
            images: 图片列表
            meta_data: 附加消息
            custom_variables: 自定义变量

     **return**:流式::

        参照链接: https://www.coze.cn/docs/developer_guides/chat_v3

        返回:
            模型话术

    """
    coze = Coze(personal_token=personal_token, public_key=public_key, private_key=private_key, oauth_app_id=oauth_app_id)
    ret_data = coze.chat_streaming(bot_id, user_id, user_message, conversation_id, files, images, meta_data, custom_variables)

    return responses.StreamingResponse(ret_data, media_type='text/plain')


@coze_router.get('/coze/chat/retrieve', summary='查看对话详情')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),))
@exec_duration(add_return=True)
async def retrieve_chat(request: Request,
                        conversation_id: str = Query(..., title='会话id'),
                        personal_token: str = Body(None, title='个人令牌', description='不传个人令牌时, 服务会自动使用团队令牌'),
                        chat_id: str = Query(..., title='对话唯一标识')):
    """
    **desc**: 查看对话详情

    **url**: http(s)://{0}.udicaria.com/u/coze/chat/retrieve

    **method**: POST

    **params**:

        <query>:
            conversation_id: 会话id(可不传)
            personal_token: personal_token(个人令牌)
            chat_id: 对话唯一标识

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    coze = Coze(personal_token=personal_token)
    ret_data = await coze.retrieve_chat(conversation_id, chat_id)

    return json_response(data=ret_data)


@coze_router.get('/coze/chat/message/list', summary='查看对话消息详情')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),))
@exec_duration(add_return=True)
async def get_message_list(request: Request,
                           conversation_id: str = Query(..., title='会话id'),
                           personal_token: str = Body(None, title='个人令牌', description='不传个人令牌时, 服务会自动使用团队令牌'),
                           chat_id: str = Query(..., title='对话唯一标识')):
    """
    **desc**: 查看对话消息详情

    **url**: http(s)://{0}.udicaria.com/u/coze/chat/message/list

    **method**: POST

    **params**:

        <query>:
            conversation_id: 会话id(可不传)
            personal_token: personal_token(个人令牌)
            chat_id: 对话唯一标识

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    coze = Coze(personal_token=personal_token)
    ret_data = await coze.get_chat_message_list(conversation_id, chat_id)

    return json_response(data=ret_data)


@coze_router.post('/coze/workflow/run', summary='执行工作流')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),))
@exec_duration(add_return=True)
async def run_workflow(request: Request,
                       workflow_id: str = Body(..., title='工作流id'),
                       parameters: list = Body(None, title='工作流参数'),
                       bot_id: str = Body(None, title='智能体id'),
                       app_id: str = Body(None, title='应用id'),
                       ext: list = Body(None, title='额外字段'),
                       is_async: bool = Body(False, title='是否异步', description='异步运行后可通过本接口返回的 execute_id 调用, 获取工作流的最终执行结果'),
                       personal_token: str = Body(None, title='个人令牌', description='不传个人令牌时, 服务会自动使用团队令牌')):
    """
    **desc**: 执行工作流

    **url**: http(s)://{0}.udicaria.com/u/coze/workflow/run

    **method**: POST

    **params**:

        <query>:
            workflow_id: 工作流id
            parameters: 工作流参数
            bot_id: 智能体id
            app_id: 应用id
            ext: 额外字段
            is_async: 是否异步 默认false  异步运行后可通过本接口返回的 execute_id 调用, 获取工作流的最终执行结果
            personal_token: 个人令牌(不传个人令牌时, 服务会自动使用团队令牌)

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    coze = Coze(personal_token=personal_token)
    ret_data = await coze.run_workflow(workflow_id, parameters=parameters, bot_id=bot_id, app_id=app_id, ext=ext, is_async=is_async)

    return json_response(data=ret_data)


@coze_router.post('/coze/workflow/run/streaming', summary='执行工作流(流式)')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),))
@exec_duration(add_return=True)
async def run_workflow_streaming(request: Request,
                                 workflow_id: str = Body(..., title='工作流id'),
                                 parameters: list = Body(None, title='工作流参数'),
                                 bot_id: str = Query(None, title='智能体id'),
                                 app_id: str = Query(None, title='应用id'),
                                 ext: list = Body(None, title='额外字段'),
                                 personal_token: str = Body(None, title='个人令牌', description='不传个人令牌时, 服务会自动使用团队令牌')):
    """
    **desc**: 执行工作流(流式)

    **url**: http(s)://{0}.udicaria.com/u/coze/workflow/run/streaming

    **method**: POST

    **params**:

        <query>:
            workflow_id: 工作流id
            parameters: 工作流参数
            bot_id: 智能体id
            app_id: 应用id
            personal_token: 个人令牌(不传个人令牌时, 服务会自动使用团队令牌)

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    coze = Coze(personal_token=personal_token)

    return responses.StreamingResponse(coze.run_workflow_streaming(workflow_id, parameters=parameters, bot_id=bot_id, app_id=app_id, ext=ext),
                                       media_type='text/plain')


@coze_router.post('/coze/temp/add', summary='添加临时数据')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),))
@exec_duration(add_return=True)
async def do_temp_data_add(request: Request, effective_days: int = Body('1', title='有效天数'), data: dict = Body(..., title='临时数据'), session=None):
    """
    **desc**: 临时数据

    **url**: http(s)://{0}.udicaria.com/u/coze/temp/add

    **method**: POST

    **params**:

        <body>:
            data: 临时数据

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    coze = await CozeTemp.create_modify(session, effective_days=effective_days, data=data)

    return json_response(data=coze.dict('id'))


@coze_router.get('/coze/temp', summary='查询临时数据')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),))
@exec_duration(add_return=True)
async def get_temp_data(request: Request, id: int = Query(..., title='新增时返回的id', embed=True), session=None):
    """
    **desc**: 临时数据

    **url**: http(s)://{0}.udicaria.com/u/coze/temp

    **method**: POST

    **params**:

        <body>:
            id: 新增时返回的id

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    coze = await CozeTemp.fetch_one(session, wheres=(CozeTemp.id == id))

    return json_response(data=coze.dict('data'))